package auth

import (
	"encoding/json"
	"fmt"

	"illuminant/config"
	"illuminant/logger"
	"illuminant/model"
	"illuminant/util"
)

const gqlGetRules = `{
  illuminant_casbin_rule {
    id
    p_type
    v0
    v1
    v2
    v3
    v4
    v5
 }
}`

const gqlDeleteRules = `mutation delete_rules($pType: String, $v0: String, $v1: String, $v2: String, $v3: String, $v4: String, $v5: String) {
  delete_illuminant_casbin_rule(where: {p_type: {_eq: $pType}, v0: {_eq: $v0}, v1: {_eq: $v1}, v2: {_eq: $v2}, v3: {_eq: $v3}, v4: {_eq: $v4}, v5: {_eq: $v5}}) {
    affected_rows
  }
}`

const gqlAddRule = `mutation insert_one_rule($pType: String!, $v0: String, $v1: String, $v2: String, $v3: String, $v4: String, $v5: String) {
  insert_illuminant_casbin_rule_one(object: {p_type: $pType, v0: $v0, v1: $v1, v2: $v2, v3: $v3, v4: $v4, v5: $v5}) {
    id
  }
}`

const gqlAddRules = `mutation insert_rules($objects: [casbin_rule_insert_input!]!) {
  insert_illuminant_casbin_rule(objects: $objects) {
    affected_rows
  }
}`

func GetRules() ([]*model.IlluminantCasbinRule, error) {
	lg := logger.GetLogger()
	cnf := config.Get()

	data, err := util.PostJson(cnf.Graphql.Endpoint, map[string]interface{}{
		"query":     gqlGetRules,
		"variables": nil,
	})
	if err != nil {
		lg.Err(err).Msg("service: GetRules -> graphql request")
		return nil, err

	}

	var resp struct {
		Data struct {
			CasbinRules []*model.IlluminantCasbinRule `json:"illuminant_casbin_rule"`
		} `json:"data"`
	}
	if err = json.Unmarshal(data, &resp); err != nil {
		lg.Err(err).Msg("service: GetRules -> json unmarshal")
		return nil, err

	}

	return resp.Data.CasbinRules, nil
}

func DeleteRules(m model.IlluminantCasbinRule) error {
	var delVars = make(map[string]interface{})
	if m.PType != "" {
		delVars["pType"] = m.PType
	}
	if m.V0 != "" {
		delVars["v0"] = m.V0
	}
	if m.V1 != "" {
		delVars["v1"] = m.V1
	}
	if m.V2 != "" {
		delVars["v2"] = m.V2
	}
	if m.V3 != "" {
		delVars["v3"] = m.V3
	}
	if m.V4 != "" {
		delVars["v4"] = m.V4
	}
	if m.V5 != "" {
		delVars["v5"] = m.V5
	}

	lg := logger.GetLogger()
	cnf := config.Get()

	_, err := util.PostJson(cnf.Graphql.Endpoint, map[string]interface{}{
		"query":     gqlDeleteRules,
		"variables": delVars,
	})
	if err != nil {
		lg.Err(err).Msg("service: DeleteRules -> graphql request")

	}

	return err
}

func AddRule(m model.IlluminantCasbinRule) error {
	lg := logger.GetLogger()
	cnf := config.Get()

	_, err := util.PostJson(cnf.Graphql.Endpoint, map[string]interface{}{
		"query": gqlAddRule,
		"variables": map[string]interface{}{
			"pType": m.PType,
			"v0":    m.V0,
			"v1":    m.V1,
			"v2":    m.V2,
			"v3":    m.V3,
			"v4":    m.V4,
			"v5":    m.V5,
		},
	})
	if err != nil {
		lg.Err(err).Msg("service: AddRule -> graphql request")
	}

	return err
}

func AddRules(objects []model.IlluminantCasbinRule) error {
	lg := logger.GetLogger()
	cnf := config.Get()

	var gqlVar = make([]map[string]interface{}, 0)
	for _, obj := range objects {
		var mVar = make(map[string]interface{})
		mVar["p_type"] = obj.PType
		mVar["v0"] = obj.V0
		mVar["v1"] = obj.V1
		mVar["v2"] = obj.V2
		mVar["v3"] = obj.V3
		mVar["v4"] = obj.V4
		mVar["v5"] = obj.V5

		gqlVar = append(gqlVar, mVar)
	}

	data, err := util.PostJson(cnf.Graphql.Endpoint, map[string]interface{}{
		"query": gqlAddRules,
		"variables": map[string]interface{}{
			"objects": gqlVar,
		},
	})
	if err != nil {
		lg.Err(err).Msg("service: AddRules -> graphql request")
		return err
	}

	resp, err := util.Graphql2RestResp(data)
	if err != nil {
		lg.Err(err).Msg("service: AddRules -> graphql response parse")
		return err
	}

	if resp.Code != util.SUCCESS {
		err = fmt.Errorf("%s", resp.Message)
		lg.Err(err).Msg("service: AddRules -> graphql response")
	}

	return err
}
